package ch.ethz.fcl.metrobuzz.data.scene.spacetime;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import ch.ethz.fcl.metrobuzz.algorithm.network.shortest_path.public_transport.PathPublic;
import ch.ethz.fcl.metrobuzz.data.MBData;
import ch.ethz.fcl.metrobuzz.data.scene.basemap.Edge;
import ch.ethz.fcl.metrobuzz.data.scene.basemap.Node;
import ch.ethz.fcl.metrobuzz.data.transit.Stop;
import ch.ethz.fcl.metrobuzz.data.transit.TransitLine;
import ch.ethz.fcl.metrobuzz.data.transit.TransitRoute;
import ch.ethz.fcl.metrobuzz.tools.MBTools;

public class Itinerary {
	private Agent agent;

	private boolean isPT;
	private ArrayList<Trip> trips = null;
	private Map<Long, Trip> tripIdMap = null;

	public Itinerary(Agent agent) {
		this.agent = agent;
		agent.setItinerary(this);

		tripIdMap = new HashMap<Long, Trip>();
		trips = new ArrayList<Trip>();
	}

	public void setPT(boolean isPT) {
		this.isPT = isPT;
	}

	public boolean isPT() {
		return isPT;
	}

	public Agent getAgent() {
		return agent;
	}

	public ArrayList<Trip> getTrips() {
		return trips;
	}

	public void addTrips(MBData data, int tripIndex, float tdep, float tarr,
			char[] ch, int start, int length) {
		String s = String.copyValueOf(ch, start, length);
		if (s.contains("kti"))
			return;

		long tripId = agent.getAgentId() * 10 + tripIndex;

		s = s.replaceAll("\n", "");
		s = s.replaceAll("\t", "");
		s = s.replaceAll(" ", "");
		MBTools.debug("dep time " + tdep + " arr time " + tarr, false);

		String[] n = s.split("===");

		if (n.length == 1)
			return;
		TransitLine line = null;
		if (data.getPublicTransit().getLines().size() > 0)
			line = data.getPublicTransit().getLine(n[2]);
		TransitRoute route = line.getRoute(n[3]);

		// add according to edges
		Stop startStop = data.getPublicTransit().getStopByStopId(n[1]);
		Stop endStop = data.getPublicTransit().getStopByStopId(n[4]);

		List<Integer> nodesIndices = getNodeIndices(data, tdep, tarr, route,
				startStop, endStop);
		addTrip(data, nodesIndices, tripId, -1, tdep, tarr, 1);
	}

	public List<Integer> getNodeIndices(MBData data, float tdep, float tarr,
			TransitRoute route, Stop start, Stop end) {
		List<Integer> nodeIndices = new ArrayList<Integer>();

		// for subway, mrt, lrt lines
		if (!route.getMode().equals("bus")) {
			// Node sourceNode = data.getScene().getNode(start.getId());
			// Node endNode = data.getScene().getNode(end.getId());

			PathPublic p = data.getAllToAllDijkstra().getPath(start, end);

			for (List<Node> paths : p.getExactPath())
				for (Node n : paths)
					nodeIndices.add(data.getScene().getNodeIndex(n.getId()));
		}
		// for bus lines
		else {
			List<Edge> interedges = route.getInterEdges(start, end);

			if (interedges == null)
				return null;

			float totalTripLength = 0;

			for (Edge e : interedges) {
				totalTripLength += e.length();
			}

			float passingTripLength = 0;
			for (int i = 0; i < interedges.size(); i++) {
				Edge edge = interedges.get(i);

				passingTripLength += edge.length();

				// measure time the trip passing the edge
				@SuppressWarnings("unused")
				float time = tdep + (tarr - tdep) * passingTripLength
						/ totalTripLength;

				// float normalizedTime = time / (24 * 60 * 60);
				// edge.addPassTripId(tripId + normalizedTime);

				int node_index = edge.getStartNodeIndex();
				nodeIndices.add(node_index);
			}

			Edge endEdge = interedges.get(interedges.size() - 1);
			int endNodeIndex = endEdge.getEndNodeIndex();
			nodeIndices.add(endNodeIndex);
		}

		return nodeIndices;
	}

	public void addTrip(MBData data, List<Integer> nodes, long tripId,
			int segmentId, float tdep, float tarr, float probability) {
		if (nodes != null && !nodes.isEmpty()) {

			Trip trip = tripIdMap.get(tripId);

			if (trip == null) {
				trip = new Trip(this, tripId);
				tripIdMap.put(tripId, trip);

				Trip.TripSegment tripSegment = trip.new TripSegment(
						data.getScene(), trip, tdep, tarr, nodes, probability);
				trip.addTripSegment(tripSegment, segmentId);
				trips.add(trip);
			} else {
				Trip.TripSegment tripSegment = trip.new TripSegment(
						data.getScene(), trip, tdep, tarr, nodes, probability);
				trip.addTripSegment(tripSegment, segmentId);
			}
		}
	}
}
